import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.DefaultListModel;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JList;

/**
 * This class represents all the modules that have list graphical representation
 * to interact with its information.
 * 
 * @author ubuntu
 */
public abstract class ListModule extends Module implements MouseListener {

  /**
   * The model of the list that contains all the objects.
   */
  DefaultListModel listModel;

  /**
   * The model of the selection that controls the way the list allows to be
   * selected.
   */
  DefaultListSelectionModel listSelectionModel;

  /**
   * Contructor! Creates a list module with single selection mode.
   */
  public ListModule() {
    this.listModel = new DefaultListModel();
    this.listSelectionModel = new DefaultListSelectionModel();
    this.listSelectionModel
        .setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
  }

  /**
   * Constructor! Creates a list module with given selection mode.
   * 
   * @param selectionMode
   *          the mode for the selectionModel.
   */
  public ListModule(int selectionMode) {
    this.listModel = new DefaultListModel();
    this.listSelectionModel = new DefaultListSelectionModel();
    this.listSelectionModel.setSelectionMode(selectionMode);
  }

  /**
   * Since it is a module it must implement this method, but at this level it
   * makes not sense to do anything.
   */
  public abstract boolean needsToBeUpdated();

  /**
   * Please daddy! update me!
   */
  protected abstract void updateMe();

  /**
   * Returns a new list created from the list model and with the selection model
   * as well. This class also will listen to all the events related to mouse
   * over the list.
   * 
   * @return a Beautiful new list!
   */
  public JList getList() {
    JList list = new JList(this.listModel);
    list.setSelectionModel(this.listSelectionModel);
    list.addMouseListener(this);
    return list;
  }

  /**
   * Removes all objects from the model.
   */
  protected void removeAllObjects() {
    this.listModel.removeAllElements();
  }

  /**
   * Adds a new object to the list model.
   * 
   * @param object
   *          the object to be added.
   */
  protected void addObject(Object object) {
    this.listModel.addElement(object);
  }

  /**
   * Iterates over the list model and erase all the selected objects.
   */
  protected void removeSelectedObjects() {
    for (int i = 0; i < this.listModel.getSize(); i++) {
      if (listSelectionModel.isSelectedIndex(i)) {
        this.listModel.remove(i);
        // To fix the position, my friend!
        i--;
      }
    }
  }

  /**
   * Checks if the object is inside the list model.
   * 
   * @param object
   *          the object, daddy! what else?
   * @return true or false!
   */
  protected boolean containsObject(Object object) {
    return this.listModel.contains(object);
  }

  /**
   * This method searches through the whole list model to find the first
   * selected object.
   * 
   * @return the first selected object or null if there is no object selected.
   */
  protected Object getFirstSelectedObject() {
    for (int i = 0; i < this.listModel.getSize(); i++) {
      if (listSelectionModel.isSelectedIndex(i)) {
        return this.listModel.get(i);
      }
    }
    return null;
  }

  /**
   * This method searches through the whole list model to find the first
   * selected object.
   * 
   * @return the first selected objects index. If there is no selected object it
   *         returns -1.
   */
  protected int getFirstSelectedIndex() {
    for (int i = 0; i < this.listModel.getSize(); i++) {
      if (listSelectionModel.isSelectedIndex(i)) {
        return i;
      }
    }
    return -1;
  }

  /**
   * Returns the size of the list model.
   * 
   * @return the size of the list model!!!
   */
  protected int getNumberOfObjects() {
    return this.listModel.size();
  }

  /**
   * This methods returns the object at given position.
   * 
   * @param index
   *          the index of the object to return!
   * @return the object in given position
   */
  protected Object getObjectAt(int index) {
    return this.listModel.getElementAt(index);
  }

  /**
   * Removes object in given position.
   * 
   * @param index
   *          the index of the object to remove.
   */
  protected void removeObjectAt(int index) {
    this.listModel.remove(index);
  }

  @Override
  public void mouseClicked(MouseEvent arg0) {
    if (arg0.getClickCount() == 1) {
      this.selectObject();
    } else {
      this.modifyObject();
    }
  }

  protected abstract void selectObject();

  protected abstract void modifyObject();

  @Override
  public void mouseEntered(MouseEvent arg0) {
  }

  @Override
  public void mouseExited(MouseEvent arg0) {
  }

  @Override
  public void mousePressed(MouseEvent arg0) {
  }

  @Override
  public void mouseReleased(MouseEvent arg0) {
  }

}
